package com.sutong.common.utils;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.digest.DigestAlgorithm;
import cn.hutool.crypto.digest.Digester;
import org.springframework.http.HttpRequest;

import java.util.Set;

/**
 * 签名工具
 *
 * @author sutong
 * @date 2024-07-11 11:06
 */
public class SignUtils {

    /**
     * 指定的header参与签名
     */
    private static final Set<String> JOIN_SIGN_HEADERS =
            CollUtil.newHashSet("accept", "content-type", "content-length");


    /**
     * 生成签名 (simple)
     *
     * @param body
     * @param secretKey
     * @return
     */
    public static String genSign(String body, String secretKey) {
        Digester md5 = new Digester(DigestAlgorithm.SHA256);
        String content = body + "." + secretKey;
        return md5.digestHex(content);
    }

    /**
     * HTTPMethod
     * Accept
     * Content-MD5
     * Content-Type
     * Date (没加)
     * Headers
     * PathAndParameters
     *
     * @return signature
     */
    public static String signature(String secretKey, HttpRequest request, String body) {
        StringBuffer signature = new StringBuffer();

        // HTTPMethod  HTTP的方法，全部大写
        String method = request.getMethod().name();
        signature.append(method.toUpperCase()).append("\n");

        // Headers  选取指定的header参与签名
        request.getHeaders().forEach((k, v) -> {
            if (JOIN_SIGN_HEADERS.contains(k.toLowerCase())) {
                signature.append(k).append(":").append(v).append("\n");
            }
        });

        // Content  只有在请求存在Body且Body为非Form形式时才计算Content
        if (contentIsJoinSign(request)) {
            signature.append(body).append("\n");
        }

        // PathAndParameters  Query和Form参数为空时，则直接使用Path，不需要添加？
        signature.append(request.getURI().getPath());
        if (StrUtil.isNotBlank(request.getURI().getQuery())) {
            signature.append("?").append(request.getURI().getQuery());
        }
        return SecureUtil.hmacSha256(secretKey).digestHex(signature.toString());
    }

    public static boolean contentIsJoinSign(HttpRequest request) {
        String contentLength = request.getHeaders().getFirst("Content-Length");
        String contentType = request.getHeaders().getFirst("Content-Type");
        return NumberUtil.parseLong(contentLength) > 0L && !StrUtil.contains(contentType, "multipart/form-data");
    }
}